iT邦幫忙

2024 iThome 鐵人賽

DAY 14
0
佛心分享-SideProject30

NUXT3xVUE3xPINIA: 從零開始寫電商系列 第 15

[Day 16] 開始第個頁面:登入/註冊頁 + Firebase: Authentication

  • 分享至 

  • xImage
  •  

這是第一次用firebase,記錄一下坑坑點點的過程。
登入
註冊

目錄

  • 新增Firebase Authentication專案
  • 在NUXT3裡設定firebase config
  • 登入
  • 註冊
  • 整合到CI前置作業
  • 閒聊碎碎念

新增Firebase Authentication專案

  1. 首先要有firebase帳號
  2. 建立專案,Build > Authentication > get started
    建立專案
    建立專案
    建立專案
  3. 然後會有跟數據分析有關的,這邊我直接使用default選項,然後勾選同意使用者條款,下一步
    建立專案
  4. 專案初始化ok後,開始使用
    開始使用
  5. 接下來選擇登入方式,由於本專案的設計就只需要email及密碼而已,而我也沒打算用真的email去測試,所以選擇“原生供應商 > 電子郵件/密碼”
    選擇登入方式
  6. 像上一步提的,我需要email, password,所以選擇“電子郵件/密碼”,下一步。
    設定登入方式
  7. 切換到“使用者”tab > “新增使用者”,把假的email、密碼輸入進去。
    新增使用者
  8. 接著,拿這個專案的SDK;專案總覽 > 專案設定 > 選擇應用程式 > 註冊應用程式
    選擇登入方式
  9. 拿取firebase的keys,接下來這步hen重要,下方有很多keys,把它給複製下來,到專案新增./plugins/firebase.ts,這樣處理是暫時的,不可能把這些keys放在專案裡,然後推到github歡迎光臨給大家看XD,後面會提我會怎麼整合進CI處理這部分:
    拿取firebase的keys
// ./plugins/firebase.ts
const firebaseConfig = {
    apiKey: "XXX",
    authDomain: "XXX.firebaseapp.com",
    projectId: "XXX",
    storageBucket: "XXX.appspot.com",
    messagingSenderId: "XXX",
    appId: "XXX",
    measurementId: "XXX"
};

新增專案到這邊告一個段落。

在NUXT3裡設定firebase config

  1. 繼續完成firebase的plugin,可以稍微看一下firebase的文件這篇說明如何初始化firebase app,這篇說明我選的登入方式該怎麼實作登入註冊功能;登入、註冊功能會用到的有:getAuth, signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut
// ./plugins/firebase.ts
import { initializeApp } from 'firebase/app';
import { getAuth, signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut } from 'firebase/auth';

// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
    apiKey: "XXX",
    authDomain: "XXX.firebaseapp.com",
    projectId: "XXX",
    storageBucket: "XXX.appspot.com",
    messagingSenderId: "XXX",
    appId: "XXX",
    measurementId: "XXX"
};
export default defineNuxtPlugin(nuxtApp => {
    const app = initializeApp(firebaseConfig);
    const auth = getAuth(app);

    nuxtApp.provide('auth', auth);
    nuxtApp.provide('signInWithEmailAndPassword', signInWithEmailAndPassword);
    nuxtApp.provide('createUserWithEmailAndPassword', createUserWithEmailAndPassword);
    nuxtApp.provide('signOut', signOut);
});

登入

./pages/login.vue裡,把登入寫好:

  1. UI:帳號、密碼,這邊為了測試方便,直接把firebase裡設定的那組寫進去。
  2. UI:錯誤訊息
  3. UI:登入按鈕
  4. UI:還不是會員?:點擊後到註冊頁
  5. 流程:flowchart畫過了,基本就是:輸入帳密 > 按下登入
    • 通過:到首頁
    • 不通過:停留原位,顯示錯誤
// ./pages/login.vue
<script setup lang="ts">
const router = useRouter();

const email: Ref<string> = ref('ecithome2024@test.com');
const password: Ref<string> = ref('aaaa123');
const status = ref({ message: '', type: '' });
const { $auth, $signInWithEmailAndPassword } = useNuxtApp();

const login = async () => {
  console.log(`login`);
  try {
    await $signInWithEmailAndPassword($auth, email.value, password.value);
    status.value = { message: '登入成功!', type: 'success' };
    // 使用 useRouter 導航
    useRouter().push('/'); // 登入後重定向到首頁
  } catch (error) {
    status.value = { message: '登入失敗!請檢查您的憑證。', type: 'error' };
  }
};

// 登入頁不需要layout
definePageMeta({
    layout: false
})
</script>

<template>
  <div>
    <form @submit.prevent="login">
      <input type="email" v-model="email" placeholder="Email">
      <input type="password" v-model="password" placeholder="Password">
      <button type="submit">Login</button>
      <NuxtLink to="/registration">還不是會員?</NuxtLink>
      <p>{{status.type}} {{status.message}}</p>
    </form>
  </div>
</template>

<style scoped>
</style>
  1. 測試一下登入成功、失敗,由於成功直接導入首頁,這邊直接截圖失敗的樣子:
    登入失敗

註冊

接著是註冊,原本的設計是除了firebase Authentication這邊要求的email及password欄位以外,另外還要提供名字、電話、地址,不過這部分我想存在firebase realtime database,我不想把登入註冊這一篇用得太複雜,所以這邊單純把firebase Authentication串好就好,等到會員頁再回來補這一塊。
註冊跟登入很像,差別是這邊使用$createUserWithEmailAndPassword

  1. UI:帳號、密碼。
  2. UI:錯誤訊息
  3. UI:註冊按鈕
  4. UI:已經是會員?:點擊後回到登入頁
  5. 流程:輸入帳密 > 按下登入
    • 通過:到首頁
    • 不通過:停留原位,顯示錯誤
// ./pages/registration.vue
<script setup lang="ts">
const router = useRouter();

const { $auth, $createUserWithEmailAndPassword } = useNuxtApp();

const email: Ref<string> = ref('ecithome2024@test.com');
const password: Ref<string> = ref('aaaa123');
const status = ref({ message: '', type: '' });

const regis = async () => {
  console.log(`regis`);
  try {
    await $createUserWithEmailAndPassword($auth, email.value, password.value)
    status.value = { message: '註冊成功!', type: 'success' };
    useRouter().push('/');
  } catch (error) {
    console.log(error)
    status.value = { message: `${error.message}`, type: 'error' };
  }
};

definePageMeta({
    layout: false
});
</script>

<template>
  <div>
    <form @submit.prevent="regis">
      <input type="email" v-model="email" placeholder="Email">
      <input type="password" v-model="password" placeholder="Password">
      <button type="submit">註冊</button>
      <NuxtLink to="/login">已經是會員?</NuxtLink>
      <p>{{status.type}} {{status.message}}</p>
    </form>
  </div>
</template>

<style scoped>
</style>

截圖一下失敗case:
註冊失敗

整合到CI前置作業

功能的部分到上面已經是差不多了,不過像前面提到的,那些firebase的keys得找個安全的地方放,所以會放在被gitignore的.env裡,環境規劃是這樣的:

  • local: .env
  • github -> 這個部分,我打算後面CI/CD再一起解釋處理
    • dev
    • prod

先處理local端,首先將firebase的keys先提出,放入專案根目錄的.env

FIREBASE_API_KEY="xxx"
FIREBASE_AUTH_DOMAIN="xxx"
FIREBASE_PROJECT_ID="xxx"
FIREBASE_STORAGE_BUCKET="xxx"
FIREBASE_MESSAGING_SENDER_ID="xxx"
FIREBASE_APP_ID="xxx"
FIREBASE_MEASUREMENT_ID="xxx"

接著到nuxt.config.js設置runtimeConfig:

export default defineNuxtConfig({
  ...
  runtimeConfig: {
    public: {
      firebase: {
        apiKey: process.env.FIREBASE_API_KEY,
        authDomain: process.env.FIREBASE_AUTH_DOMAIN,
        projectId: process.env.FIREBASE_PROJECT_ID,
        storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
        messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
        appId: process.env.FIREBASE_APP_ID,
        measurementId: process.env.FIREBASE_MEASUREMENT_ID,
      }
    }
  },
  ...
})

最後修改一下firebase的plugin./plugins/firebase.ts,將哈扣改成環境變數:

...
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
export default defineNuxtPlugin(nuxtApp => {
    const config = useRuntimeConfig();
    const firebaseConfig = {
        apiKey: config.public.firebase.apiKey,
        authDomain: config.public.firebase.authDomain,
        projectId: config.public.firebase.projectId,
        storageBucket: config.public.firebase.storageBucket,
        messagingSenderId: config.public.firebase.messagingSenderId,
        appId: config.public.firebase.appId,
        measurementId: config.public.firebase.measurementId
    };
    ...
});

再跑一下測試,沒毛病就完成了!

閒聊碎碎念

知道我的SideProject30教學成分不居多(什麼文法XD)可能主題也不這麼吸引人(就是百年不難得一見的電商(究竟是什麼文法XD))。主要想藉由參加鐵人賽,半逼迫自己完成一個side project;其實一邊在做專案時,一邊也在想,有榮幸經歷AI的年代,也許很鉅細彌遺的教學不是最主要了,我們可能要更重視知道要做什麼,且將需求有條有理的整理出來,當然在剛轉工程師的時候單純google也有這種感覺,但不知道為什麼在現在體悟更深。沒原因的,忽然很想把這些感觸寫出來。接下來的自己繼續加油!

PS. 真的是滿想切腹的...Day15(昨天)文章明明都預寫完了,somehow就是沒發出去...所以鐵人賽就失敗了....不過我還是會照發T_T好煩喔


上一篇
[Day 14] 設定i18n
下一篇
[Day 15] 來做部分共用的components吧+設定ICON!!
系列文
NUXT3xVUE3xPINIA: 從零開始寫電商17
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言